﻿using System.Collections.Generic;
using System.Linq;
using System.Windows;
using DeepZoomPivotConstructor.DTBuilderLib;
using DeepZoomSLUtilities.HotSpots;

namespace DeepZoomSLUtilities
{
    /// <summary>
    /// Holds onto hot spot information, and helps
    /// with finding out if there was a hit, etc.
    /// </summary>
    internal class SubImageHotSpotInfo
    {
        /// <summary>
        /// The bounding rect of this sub image, in global coordinates, of course.
        /// </summary>
        Rect boundary;

        /// <summary>
        /// The scale factor to use when converting from
        /// global coordinates to the subimage local ones.
        /// </summary>
        double scaleGlobalToLocal;

        /// <summary>
        /// Convert to our internal hot spot info. Assume that the subImageInfo is originally scaled to 1.0...
        /// </summary>
        /// <param name="hsInfo"></param>
        public SubImageHotSpotInfo(DZTalkVisualMetaData subImageInfo, DZHotSpotMetaData[] hsInfo)
        {
            allHotSpots = new HotSpotInfo[hsInfo.Length];
            for (int index = 0; index < hsInfo.Length; index++)
            {
                allHotSpots[index] = new HotSpotInfo(hsInfo[index]);
                allHotSpots[index].SubImage = this;
            }

            boundary = new Rect(subImageInfo.X,
                subImageInfo.Y,
                subImageInfo.Width,
                subImageInfo.Height);

            scaleGlobalToLocal = 1.0 / subImageInfo.Width;
        }

        /// <summary>
        /// Internal list of all the hot spots we know about
        /// </summary>
        HotSpotInfo[] allHotSpots;

        /// <summary>
        /// Returns true if this sub image contains the particular msi point
        /// </summary>
        /// <param name="msiDZGlobalPoint">Point in the DZ image coordinates (0,1)</param>
        /// <returns></returns>
        internal bool Contains(Point msiDZGlobalPoint)
        {
            ///
            /// First, determine if we are even in this sub-image
            /// 

            return boundary.Contains(msiDZGlobalPoint);
        }

        #region Coordinate Transforms

        /// <summary>
        /// Given a point in DZ global coordinates, convert it to local
        /// coordinates
        /// </summary>
        /// <param name="msiDZGlobalPoint">Point in DZ global coordinates</param>
        /// <returns>Poitn in DZ local coordinates</returns>
        internal Point ConvertSubimageToLocal(Point msiDZGlobalPoint)
        {
            return new Point((msiDZGlobalPoint.X - boundary.X) * scaleGlobalToLocal,
                (msiDZGlobalPoint.Y - boundary.Y) * scaleGlobalToLocal);
        }

        /// <summary>
        /// Convert from local coordinates to sub images a single Point structure
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        internal Point ConvertLocalToSubImage(Point point)
        {
            return new Point(point.X / scaleGlobalToLocal + boundary.X,
                point.Y / scaleGlobalToLocal + boundary.Y);
        }

        /// <summary>
        /// Converts a rect from local coordinates to global ones
        /// </summary>
        /// <param name="localRect"></param>
        /// <returns></returns>
        internal Rect ConvertLocalToSubImage(Rect localRect)
        {
            Point ul = ConvertLocalToSubImage(new Point(localRect.Left, localRect.Top));
            Point ll = ConvertLocalToSubImage(new Point(localRect.Right, localRect.Bottom));

            return new Rect(ul, ll);
        }

        #endregion

        /// <summary>
        /// Returns all active hot spots
        /// </summary>
        /// <param name="msiSubImageLocalPoint">The point in coordinates local to this sub image</param>
        /// <returns></returns>
        internal IEnumerable<HotSpotInfo> FindActiveHotspots(Point msiSubImageLocalPoint)
        {
            ///
            /// Next, now that we know we are in the game, check to see if there is a hit
            /// in our list
            /// 

            var activeHS = from hs in allHotSpots
                           where hs.ContainsPoint(msiSubImageLocalPoint)
                           select hs;

            return activeHS;
        }

        /// <summary>
        /// Look at the hot spots we know about, and count the number of centering ones.
        /// </summary>
        /// <returns></returns>
        internal int NumberCenteringHS()
        {
            return allHotSpots.Select(h => h.HasMouseCentering()).Count();
        }

        /// <summary>
        /// Find the n't centering HS, and return it!
        /// </summary>
        /// <param name="nthHSToReturn"></param>
        /// <returns></returns>
        internal HotSpotInfo GetNthCenteringHS(int nthHSToReturn)
        {
            return allHotSpots.Where(h => h.HasMouseCentering()).Skip(nthHSToReturn).FirstOrDefault();
        }
    }
}
